package com.lhb.mvnbook.account.persist;

import org.dom4j.Document;
import org.dom4j.DocumentException;
import org.dom4j.DocumentFactory;
import org.dom4j.Element;
import org.dom4j.io.OutputFormat;
import org.dom4j.io.SAXReader;
import org.dom4j.io.XMLWriter;

import java.io.*;
import java.util.List;

public class AccountPersistServiceImpl implements AccountPersistService {
    private String file;
    private SAXReader reader = new SAXReader();

    @Override
    public Account createAccount(Account account) throws AccountPersistException {
        Document document = readDocument();
        Element accounts = document.getRootElement().element(ELEMENT_ACCOUNTS);
        Element newAccount = accounts.addElement(ELEMENT_ACCOUNT);
        newAccount.addElement(ACCOUNT_ID).addText(account.getId());
        newAccount.addElement(ACCOUNT_NAME).addText(account.getName());
        newAccount.addElement(ACCOUNT_EMAIL).addText(account.getEmail());
        newAccount.addElement(ACCOUNT_PASSWORD).addText(account.getPassword());
        newAccount.addElement(ACCOUNT_ACTIVATED).addText(account.isActivated()?"true":"false");
        writeDocument(document);
        return account;
    }

    private Document readDocument() throws AccountPersistException {
        File dataFile = new File(file);
        if(!dataFile.exists()){
            dataFile.getParentFile().mkdirs();
            Document doc = DocumentFactory.getInstance().createDocument();
            Element element = doc.addElement(ELEMENT_ROOT);
            element.addElement(ELEMENT_ACCOUNTS);
            writeDocument(doc);
        }
        try {
            return reader.read(dataFile);
        } catch (DocumentException e) {
            throw new AccountPersistException("Unable to read persist data xml", e);
        }
    }

    private void writeDocument(Document doc) throws AccountPersistException {
        Writer out = null;
        try{
            out = new OutputStreamWriter(new FileOutputStream(file), "utf-8");
            XMLWriter xmlWriter = new XMLWriter(out, OutputFormat.createPrettyPrint());
            xmlWriter.write(doc);
        } catch (IOException e){
            throw new AccountPersistException("Unable to write persist data xml", e);
        } finally {
            try {
                if (out != null)  out.close();
            } catch (IOException e) {
                throw new AccountPersistException("Unable to close persist data xml writer", e);
            }
        }
    }

    @Override
    public Account readAccount(String id) throws AccountPersistException {
        Document document = readDocument();
        Element accounts = document.getRootElement().element(ELEMENT_ACCOUNTS);
        for(Element accountEle : (List<Element>) accounts.elements()) {
            if(accountEle.elementText(ACCOUNT_ID).equals(id)) {
                return buildAccount(accountEle);
            }
        }
        return null;
    }

    private Account buildAccount(Element element) {
        Account account = new Account();
        account.setId(element.elementText(ACCOUNT_ID));
        account.setName(element.elementText(ACCOUNT_NAME));
        account.setEmail(element.elementText(ACCOUNT_EMAIL));
        account.setPassword(element.elementText(ACCOUNT_PASSWORD));
        account.setActivated("true".equals(element.elementText(ACCOUNT_ACTIVATED)));
        return account;
    }

    @Override
    public Account updateAccount(Account account) throws AccountPersistException {
        Document document = readDocument();
        Element accounts = document.getRootElement().element(ELEMENT_ACCOUNTS);
        for(Element accountEle : (List<Element>) accounts.elements()) {
            if(accountEle.elementText(ACCOUNT_ID).equals(account.getId())) {
                accountEle.element(ACCOUNT_NAME).setText(account.getName());
                accountEle.element(ACCOUNT_EMAIL).setText(account.getEmail());
                accountEle.element(ACCOUNT_PASSWORD).setText(account.getPassword());
                accountEle.element(ACCOUNT_ACTIVATED).setText(account.isActivated() ? "true": "false");
                // 写入到XML文档
                writeDocument(document);
                return readAccount(account.getId());
            }
        }
        return null;
    }

    @Override
    public void deleteAccount(String id) throws AccountPersistException {
        Document document = readDocument();
        Element accounts = document.getRootElement().element(ELEMENT_ACCOUNTS);
        for(Element accountEle : (List<Element>) accounts.elements()) {
            if (accountEle.elementText(ACCOUNT_ID).equals(id)) {
                accounts.remove(accountEle);
            }
        }
        writeDocument(document);
    }

    public String getFile() {
        return file;
    }

    public void setFile(String file) {
        this.file = file;
    }

    private static final String ELEMENT_ROOT = "account-persist";
    private static final String ELEMENT_ACCOUNTS="accounts";
    private static final String ELEMENT_ACCOUNT="account";
    private static final String ACCOUNT_ID="id";
    private static final String ACCOUNT_NAME="name";
    private static final String ACCOUNT_EMAIL="email";
    private static final String ACCOUNT_PASSWORD="password";
    private static final String ACCOUNT_ACTIVATED="activated";
}
